package offer;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ZhanBo
 * @date 2020/7/4
 */
public class Solution14 {

    public static void main(String[] args) {
        System.out.println(cuttingRope2(120));
    }

    /**
     * 剑指 Offer 14- I. 剪绳子  中等
     * 给你一根长度为 n 的绳子，请把绳子剪成整数长度的 m 段（m、n都是整数，n>1并且m>1），
     * 每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少？
     * 例如，当绳子的长度是8时，我们把它剪成长度分别为2、3、3的三段，此时得到的最大乘积是18。
     *
     * 输入: 2
     * 输出: 1
     * 解释: 2 = 1 + 1, 1 × 1 = 1
     *
     * 输入: 10
     * 输出: 36
     * 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
     *
     * 解题思路：
     *      当n>3时候，无论n多大，最终都会拆为2 和 3
     *
     * @param n
     * @return
     */
    public static  int cuttingRope(int n) {
        if (n == 2 || n ==3){
            return n-1;
        }
        int result = 1;
        List<Integer> list = new ArrayList<>();
        while (n>0){
            //优先拆分为3
            if (n-3>1 || n-3==0){
                list.add(3);
                n-=3;
            }else {
                list.add(2);
                n-=2;
            }
            if (n==0){
                break;
            }
        }
        //计算结果乘积
        result *= list.stream().mapToInt(integer -> integer).reduce(1, (a, b) -> a * b);
        return result;
    }



    public static int cuttingRope2(int n) {
        if(n <= 3) {
            return n - 1;
        }
        int a = n / 3, b = n % 3;
        if(b == 0) {
            return (int)Math.pow(3, a);
        }
        if(b == 1) {
            return (int)Math.pow(3, a - 1) * 4;
        }
        return (int)((Math.pow(3, a) * 2)%1000000007);
    }


    /**
     *
     * 剑指 Offer 14- II. 剪绳子 II
     * 给你一根长度为 n 的绳子，请把绳子剪成整数长度的 m 段（m、n都是整数，n>1并且m>1），
     * 每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]*k[1]*...*k[m - 1] 可能的最大乘积是多少？
     * 例如，当绳子的长度是8时，我们把它剪成长度分别为2、3、3的三段，此时得到的最大乘积是18。
     * 答案需要取模 1e9+7（1000000007），如计算初始结果为：1000000008，请返回 1。
     * 输入: 2
     * 输出: 1
     * 解释: 2 = 1 + 1, 1 × 1 = 1
     * @param n
     * @return
     */
    public static int cuttingRope3(int n) {
        if(n <= 3) {
            return n - 1;
        }
        int b = n % 3, p = 1000000007;
        long rem = 1, x = 3;
        for(int a = n / 3 - 1; a > 0; a /= 2) {
            if(a % 2 == 1) {
                rem = (rem * x) % p;
            }
            x = (x * x) % p;
        }
        if(b == 0) {
            return (int)(rem * 3 % p);
        }
        if(b == 1) {
            return (int)(rem * 4 % p);
        }
        return (int)(rem * 6 % p);
    }

}
